package com.flyqiu.common.crypto.sm;

import cn.hutool.core.util.HexUtil;
import cn.hutool.crypto.BCUtil;
import cn.hutool.crypto.SmUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.SM2;
import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;


/**
 * 国密工具
 */
public class FlyQiuSmTools {
    /**
     * 生成秘钥对
     *
     * @return 公钥和私钥
     */
    public static FlyQiuSm2KeyModel generatorSm2() {
        return generatorSm2(SM2Engine.Mode.C1C3C2);
    }

    public static FlyQiuSm2KeyModel generatorSm2(SM2Engine.Mode mode) {
        SM2 sm2 = SmUtil.sm2();
        sm2.setMode(mode);
        String publicKey = HexUtil.encodeHexStr(((BCECPublicKey) sm2.getPublicKey()).getQ().getEncoded(false)).toUpperCase();
        String privateKey = HexUtil.encodeHexStr(BCUtil.encodeECPrivateKey(sm2.getPrivateKey())).toUpperCase();
        FlyQiuSm2KeyModel flyQiuSm2KeyModel = new FlyQiuSm2KeyModel();
        flyQiuSm2KeyModel.setPrivateKey(privateKey);
        flyQiuSm2KeyModel.setPublicKey(publicKey);
        flyQiuSm2KeyModel.setMode(mode);
        return flyQiuSm2KeyModel;
    }

    /**
     * 加密
     *
     * @param smKeyModel 公钥
     * @param data       明文
     * @return 密文
     */
    public static String sm2Encrypt(String data, BaseSmKeyModel smKeyModel) {
        SM2 sm2 = SmUtil.sm2(smKeyModel.getPublicKey(), smKeyModel.getPublicKey());
        sm2.setMode(smKeyModel.getMode());
        String result = sm2.encryptHex(data.getBytes(), KeyType.PublicKey);
        // 加密后，密文前面会有04，需要去掉
        result = result.substring(2);
        return result;
    }

    /**
     * 解密
     *
     * @param smKeyModel 私钥
     * @param data       密文
     * @return 明文
     */
    public static String sm2Decrypt(String data, BaseSmKeyModel smKeyModel) {
        // 确定前端不会加04，所以后端直接加（上面处理方式可能造成报错（Invalid point coordinates）：原因前端加密后密文自带04开头）
        if (!data.startsWith("04")) {
            data = "04" + data;
        }
        SM2 sm2 = SmUtil.sm2(smKeyModel.getPrivateKey(), smKeyModel.getPublicKey());
        sm2.setMode(smKeyModel.getMode());
        return sm2.decryptStr(data, KeyType.PrivateKey);
    }

    /**
     * sm3签名
     *
     * @param data 待签名的数据
     * @return String
     */
    public static String sm3Sing(String data) {
        return SmUtil.sm3(data);
    }


}
